#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Matplotlib 样式定制示例
演示如何定制图形样式、主题和美化技巧
"""

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.style as mplstyle
from matplotlib import cm
import matplotlib.patches as patches
import seaborn as sns

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False

def style_gallery():
    """内置样式库展示"""
    print("=== 内置样式库展示 ===")
    
    # 创建示例数据
    x = np.linspace(0, 2*np.pi, 50)
    y1 = np.sin(x)
    y2 = np.cos(x)
    
    # 获取可用样式
    available_styles = ['default', 'classic', 'seaborn', 'ggplot', 'bmh', 'dark_background']
    
    fig, axes = plt.subplots(2, 3, figsize=(15, 10))
    fig.suptitle('Matplotlib 内置样式展示', fontsize=16)
    
    for idx, style_name in enumerate(available_styles):
        row, col = idx // 3, idx % 3
        ax = axes[row, col]
        
        # 应用样式
        with plt.style.context(style_name):
            ax.plot(x, y1, linewidth=2, label='sin(x)')
            ax.plot(x, y2, linewidth=2, label='cos(x)')
            ax.set_title(f'{style_name} 样式')
            ax.legend()
            ax.grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.show()

def color_schemes():
    """颜色方案示例"""
    print("=== 颜色方案示例 ===")
    
    fig, axes = plt.subplots(2, 3, figsize=(15, 10))
    fig.suptitle('不同颜色方案展示', fontsize=16)
    
    # 创建数据
    categories = ['类别A', '类别B', '类别C', '类别D', '类别E']
    values = [23, 45, 56, 78, 32]
    
    # 不同颜色方案
    color_schemes = [
        (['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7'], '温暖色调'),
        (['#2C3E50', '#34495E', '#7F8C8D', '#95A5A6', '#BDC3C7'], '冷色调'),
        (['#E74C3C', '#E67E22', '#F39C12', '#F1C40F', '#2ECC71'], '彩虹色'),
        (['#9B59B6', '#8E44AD', '#3498DB', '#2980B9', '#1ABC9C'], '蓝紫色'),
        (['#FF9999', '#66B2FF', '#99FF99', '#FFCC99', '#FF99CC'], '粉嫩色'),
        (plt.cm.Set3(np.linspace(0, 1, 5)), 'Set3色彩映射')
    ]
    
    for idx, (colors, scheme_name) in enumerate(color_schemes):
        row, col = idx // 3, idx % 3
        ax = axes[row, col]
        
        bars = ax.bar(categories, values, color=colors)
        ax.set_title(scheme_name)
        ax.set_ylabel('数值')
        
        # 旋转x轴标签
        plt.setp(ax.get_xticklabels(), rotation=45, ha='right')
    
    plt.tight_layout()
    plt.show()

def font_customization():
    """字体定制示例"""
    print("=== 字体定制示例 ===")
    
    fig, axes = plt.subplots(2, 2, figsize=(12, 10))
    fig.suptitle('字体定制展示', fontsize=20, fontweight='bold')
    
    x = np.linspace(0, 2*np.pi, 100)
    y = np.sin(x)
    
    # 子图1: 不同字体大小
    ax1 = axes[0, 0]
    ax1.plot(x, y, linewidth=2)
    ax1.set_title('不同字体大小', fontsize=16, fontweight='bold')
    ax1.set_xlabel('X轴标签', fontsize=14)
    ax1.set_ylabel('Y轴标签', fontsize=12)
    ax1.tick_params(axis='both', labelsize=10)
    
    # 子图2: 不同字体样式
    ax2 = axes[0, 1]
    ax2.plot(x, y, linewidth=2)
    ax2.set_title('字体样式变化', fontsize=14, style='italic')
    ax2.set_xlabel('X轴 (粗体)', fontweight='bold')
    ax2.set_ylabel('Y轴 (斜体)', style='italic')
    
    # 子图3: 字体颜色
    ax3 = axes[1, 0]
    ax3.plot(x, y, linewidth=2)
    ax3.set_title('彩色字体', fontsize=14, color='red')
    ax3.set_xlabel('蓝色X轴', color='blue', fontsize=12)
    ax3.set_ylabel('绿色Y轴', color='green', fontsize=12)
    ax3.tick_params(colors='purple')
    
    # 子图4: 组合样式
    ax4 = axes[1, 1]
    ax4.plot(x, y, linewidth=2)
    ax4.set_title('组合样式', fontsize=16, fontweight='bold', 
                 color='darkblue', style='italic')
    ax4.set_xlabel('X轴', fontsize=14, fontweight='bold', color='darkred')
    ax4.set_ylabel('Y轴', fontsize=14, fontweight='bold', color='darkgreen')
    
    plt.tight_layout()
    plt.show()

def line_styles_markers():
    """线型和标记样式"""
    print("=== 线型和标记样式 ===")
    
    fig, axes = plt.subplots(2, 2, figsize=(12, 10))
    fig.suptitle('线型和标记样式展示', fontsize=16)
    
    x = np.linspace(0, 2*np.pi, 20)
    
    # 子图1: 不同线型
    ax1 = axes[0, 0]
    line_styles = ['-', '--', '-.', ':']
    line_labels = ['实线', '虚线', '点划线', '点线']
    
    for i, (style, label) in enumerate(zip(line_styles, line_labels)):
        y = np.sin(x + i*np.pi/6)
        ax1.plot(x, y, linestyle=style, linewidth=3, label=label)
    
    ax1.set_title('线型样式')
    ax1.legend()
    ax1.grid(True, alpha=0.3)
    
    # 子图2: 不同标记
    ax2 = axes[0, 1]
    markers = ['o', 's', '^', 'D', 'v', '*', 'p', 'h']
    marker_labels = ['圆', '方', '上三角', '菱形', '下三角', '星', '五角', '六角']
    
    for i, (marker, label) in enumerate(zip(markers[:6], marker_labels[:6])):
        y = 0.8 + i*0.2 + 0.1*np.sin(x)
        ax2.plot(x[::3], y[::3], marker=marker, markersize=8, 
                linewidth=2, label=label)
    
    ax2.set_title('标记样式')
    ax2.legend()
    ax2.grid(True, alpha=0.3)
    
    # 子图3: 线宽变化
    ax3 = axes[1, 0]
    line_widths = [1, 2, 3, 4, 5]
    
    for i, width in enumerate(line_widths):
        y = np.sin(x + i*np.pi/8)
        ax3.plot(x, y, linewidth=width, label=f'宽度 {width}')
    
    ax3.set_title('线宽变化')
    ax3.legend()
    ax3.grid(True, alpha=0.3)
    
    # 子图4: 透明度效果
    ax4 = axes[1, 1]
    alphas = [0.2, 0.4, 0.6, 0.8, 1.0]
    
    for i, alpha in enumerate(alphas):
        y = np.sin(x + i*np.pi/8)
        ax4.plot(x, y, linewidth=4, alpha=alpha, label=f'透明度 {alpha}')
    
    ax4.set_title('透明度效果')
    ax4.legend()
    ax4.grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.show()

def advanced_customization():
    """高级定制技巧"""
    print("=== 高级定制技巧 ===")
    
    # 创建自定义rcParams
    custom_params = {
        'figure.figsize': (12, 8),
        'axes.linewidth': 2,
        'axes.spines.left': True,
        'axes.spines.bottom': True,
        'axes.spines.top': False,
        'axes.spines.right': False,
        'xtick.direction': 'inout',
        'ytick.direction': 'inout',
        'xtick.major.size': 6,
        'ytick.major.size': 6,
        'xtick.minor.size': 3,
        'ytick.minor.size': 3,
        'grid.alpha': 0.3,
        'grid.linewidth': 1,
    }
    
    with plt.rcContext(custom_params):
        fig, axes = plt.subplots(2, 2, figsize=(12, 10))
        fig.suptitle('高级定制技巧展示', fontsize=16)
        
        # 子图1: 自定义坐标轴
        ax1 = axes[0, 0]
        x = np.linspace(0, 10, 100)
        y = np.sin(x) * np.exp(-x/10)
        
        ax1.plot(x, y, linewidth=3, color='#2E86C1')
        ax1.fill_between(x, y, alpha=0.3, color='#AED6F1')
        ax1.set_title('填充区域图', fontsize=14, pad=15)
        ax1.set_xlabel('时间')
        ax1.set_ylabel('幅度')
        ax1.grid(True)
        
        # 添加注释
        max_idx = np.argmax(y)
        ax1.annotate(f'最大值: ({x[max_idx]:.1f}, {y[max_idx]:.2f})',
                    xy=(x[max_idx], y[max_idx]), xytext=(7, 0.6),
                    arrowprops=dict(arrowstyle='->', color='red', lw=2),
                    fontsize=12, color='red')
        
        # 子图2: 双轴图
        ax2 = axes[0, 1]
        x = np.arange(10)
        y1 = np.random.randint(20, 100, 10)
        y2 = np.random.rand(10) * 5
        
        color1, color2 = '#E74C3C', '#3498DB'
        
        line1 = ax2.plot(x, y1, 'o-', color=color1, linewidth=3, 
                        markersize=8, label='数量')
        ax2.set_xlabel('时间')
        ax2.set_ylabel('数量', color=color1, fontweight='bold')
        ax2.tick_params(axis='y', labelcolor=color1)
        
        ax2_twin = ax2.twinx()
        line2 = ax2_twin.plot(x, y2, 's-', color=color2, linewidth=3, 
                             markersize=8, label='比率')
        ax2_twin.set_ylabel('比率', color=color2, fontweight='bold')
        ax2_twin.tick_params(axis='y', labelcolor=color2)
        
        ax2.set_title('双轴图表', fontsize=14, pad=15)
        
        # 合并图例
        lines = line1 + line2
        labels = [l.get_label() for l in lines]
        ax2.legend(lines, labels, loc='upper left')
        
        # 子图3: 极坐标图
        ax3 = plt.subplot(2, 2, 3, projection='polar')
        theta = np.linspace(0, 2*np.pi, 8, endpoint=False)
        r = [4, 7, 5, 3, 6, 8, 2, 4]
        colors = plt.cm.viridis(np.linspace(0, 1, len(r)))
        
        bars = ax3.bar(theta, r, width=2*np.pi/len(theta), 
                      color=colors, alpha=0.8)
        ax3.set_title('极坐标柱状图', pad=20)
        
        # 子图4: 错误条图
        ax4 = axes[1, 1]
        x = np.arange(6)
        y = [20, 35, 30, 35, 27, 40]
        yerr = [2, 3, 4, 1, 2, 3]
        
        bars = ax4.bar(x, y, yerr=yerr, capsize=10, 
                      color=['#FF6B6B', '#4ECDC4', '#45B7D1', 
                            '#96CEB4', '#FFEAA7', '#DDA0DD'],
                      alpha=0.8, edgecolor='black', linewidth=1)
        
        ax4.set_title('错误条柱状图', fontsize=14, pad=15)
        ax4.set_xlabel('类别')
        ax4.set_ylabel('数值')
        
        # 在柱子上添加数值
        for bar, value in zip(bars, y):
            height = bar.get_height()
            ax4.text(bar.get_x() + bar.get_width()/2., height + 1,
                    f'{value}', ha='center', va='bottom', fontweight='bold')
    
    plt.tight_layout()
    plt.show()

def seaborn_integration():
    """Seaborn集成示例"""
    print("=== Seaborn集成示例 ===")
    
    # 设置seaborn样式
    sns.set_style("whitegrid")
    palette = sns.color_palette("husl", 8)
    
    fig, axes = plt.subplots(2, 2, figsize=(12, 10))
    fig.suptitle('Seaborn 样式集成', fontsize=16)
    
    # 生成示例数据
    np.random.seed(42)
    n = 100
    x = np.random.randn(n)
    y = x + np.random.randn(n) * 0.5
    
    # 子图1: 散点图
    ax1 = axes[0, 0]
    ax1.scatter(x, y, c=palette[0], alpha=0.7, s=50)
    ax1.set_title('Seaborn样式散点图')
    ax1.set_xlabel('X变量')
    ax1.set_ylabel('Y变量')
    
    # 子图2: 分布图
    ax2 = axes[0, 1]
    ax2.hist(x, bins=20, color=palette[1], alpha=0.7, edgecolor='black')
    ax2.set_title('分布直方图')
    ax2.set_xlabel('数值')
    ax2.set_ylabel('频率')
    
    # 子图3: 箱线图
    ax3 = axes[1, 0]
    data = [np.random.normal(0, std, 100) for std in range(1, 4)]
    bp = ax3.boxplot(data, patch_artist=True)
    
    for patch, color in zip(bp['boxes'], palette[2:5]):
        patch.set_facecolor(color)
        patch.set_alpha(0.7)
    
    ax3.set_title('箱线图')
    ax3.set_xlabel('组别')
    ax3.set_ylabel('数值')
    
    # 子图4: 热力图
    ax4 = axes[1, 1]
    data_matrix = np.random.rand(5, 5)
    im = ax4.imshow(data_matrix, cmap='viridis', aspect='auto')
    
    # 添加数值标签
    for i in range(5):
        for j in range(5):
            ax4.text(j, i, f'{data_matrix[i, j]:.2f}',
                    ha='center', va='center', color='white', fontweight='bold')
    
    ax4.set_title('热力图')
    plt.colorbar(im, ax=ax4)
    
    plt.tight_layout()
    plt.show()

def custom_theme_example():
    """自定义主题示例"""
    print("=== 自定义主题示例 ===")
    
    # 定义自定义主题
    dark_theme = {
        'figure.facecolor': '#1e1e1e',
        'axes.facecolor': '#2d2d2d',
        'axes.edgecolor': '#888888',
        'axes.linewidth': 1.5,
        'axes.grid': True,
        'axes.grid.axis': 'both',
        'grid.color': '#444444',
        'grid.linewidth': 0.8,
        'text.color': '#ffffff',
        'axes.labelcolor': '#ffffff',
        'xtick.color': '#ffffff',
        'ytick.color': '#ffffff',
        'axes.titlecolor': '#ffffff',
        'figure.edgecolor': '#1e1e1e'
    }
    
    with plt.rcContext(dark_theme):
        fig, axes = plt.subplots(2, 2, figsize=(12, 10))
        fig.suptitle('自定义深色主题', fontsize=16, color='white')
        
        # 子图1: 线图
        ax1 = axes[0, 0]
        x = np.linspace(0, 4*np.pi, 100)
        colors = ['#FF6B6B', '#4ECDC4', '#45B7D1']
        
        for i, color in enumerate(colors):
            y = np.sin(x + i*np.pi/3)
            ax1.plot(x, y, color=color, linewidth=3, label=f'曲线{i+1}')
        
        ax1.set_title('多彩线图')
        ax1.legend()
        
        # 子图2: 柱状图
        ax2 = axes[0, 1]
        categories = ['A', 'B', 'C', 'D', 'E']
        values = [23, 45, 56, 78, 32]
        colors_bar = ['#FF9999', '#66B2FF', '#99FF99', '#FFCC99', '#FF99CC']
        
        bars = ax2.bar(categories, values, color=colors_bar, alpha=0.8)
        ax2.set_title('彩色柱状图')
        ax2.set_ylabel('数值')
        
        # 子图3: 散点图
        ax3 = axes[1, 0]
        np.random.seed(42)
        x_scatter = np.random.randn(100)
        y_scatter = np.random.randn(100)
        colors_scatter = np.random.rand(100)
        
        scatter = ax3.scatter(x_scatter, y_scatter, c=colors_scatter, 
                             cmap='plasma', alpha=0.7, s=50)
        ax3.set_title('彩色散点图')
        plt.colorbar(scatter, ax=ax3)
        
        # 子图4: 饼图
        ax4 = axes[1, 1]
        sizes = [30, 25, 20, 15, 10]
        colors_pie = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7']
        
        wedges, texts, autotexts = ax4.pie(sizes, colors=colors_pie, 
                                          autopct='%1.1f%%', startangle=90)
        
        # 设置文字颜色
        for text in texts:
            text.set_color('white')
        for autotext in autotexts:
            autotext.set_color('black')
            autotext.set_fontweight('bold')
        
        ax4.set_title('饼图')
    
    plt.tight_layout()
    plt.show()

def publication_ready_plots():
    """学术出版级图表"""
    print("=== 学术出版级图表 ===")
    
    # 设置出版级参数
    pub_params = {
        'figure.figsize': (10, 6),
        'font.size': 12,
        'axes.linewidth': 1.5,
        'axes.spines.left': True,
        'axes.spines.bottom': True,
        'axes.spines.top': False,
        'axes.spines.right': False,
        'xtick.major.size': 5,
        'xtick.minor.size': 3,
        'ytick.major.size': 5,
        'ytick.minor.size': 3,
        'xtick.direction': 'in',
        'ytick.direction': 'in',
        'legend.frameon': False,
        'legend.fontsize': 10,
    }
    
    with plt.rcContext(pub_params):
        fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
        
        # 图1: 科学数据图
        x = np.linspace(0, 10, 100)
        y1 = np.exp(-x/3) * np.sin(2*x)
        y2 = np.exp(-x/3) * np.cos(2*x)
        
        ax1.plot(x, y1, 'b-', linewidth=2, label='实验组')
        ax1.plot(x, y2, 'r--', linewidth=2, label='对照组')
        ax1.fill_between(x, y1-0.1, y1+0.1, alpha=0.2, color='blue')
        ax1.fill_between(x, y2-0.1, y2+0.1, alpha=0.2, color='red')
        
        ax1.set_xlabel('时间 (s)', fontsize=12, fontweight='bold')
        ax1.set_ylabel('信号强度 (mV)', fontsize=12, fontweight='bold')
        ax1.set_title('(A) 信号衰减对比', fontsize=14, fontweight='bold', loc='left')
        ax1.legend(loc='upper right')
        ax1.grid(True, alpha=0.3)
        
        # 图2: 统计结果图
        categories = ['实验1', '实验2', '实验3', '实验4']
        means = [85, 78, 92, 88]
        errors = [3, 4, 2, 3]
        
        x_pos = np.arange(len(categories))
        bars = ax2.bar(x_pos, means, yerr=errors, capsize=5, 
                      color='lightblue', edgecolor='black', linewidth=1,
                      error_kw={'linewidth': 2, 'ecolor': 'black'})
        
        ax2.set_xlabel('实验条件', fontsize=12, fontweight='bold')
        ax2.set_ylabel('效率 (%)', fontsize=12, fontweight='bold')
        ax2.set_title('(B) 实验效率对比', fontsize=14, fontweight='bold', loc='left')
        ax2.set_xticks(x_pos)
        ax2.set_xticklabels(categories)
        ax2.set_ylim(0, 100)
        
        # 添加统计显著性标记
        ax2.plot([0, 1], [95, 95], 'k-', linewidth=1)
        ax2.plot([0, 0], [93, 95], 'k-', linewidth=1)
        ax2.plot([1, 1], [93, 95], 'k-', linewidth=1)
        ax2.text(0.5, 97, '**', ha='center', fontsize=14, fontweight='bold')
        
        # 在柱子上添加数值
        for i, (bar, mean, error) in enumerate(zip(bars, means, errors)):
            ax2.text(bar.get_x() + bar.get_width()/2, mean + error + 1,
                    f'{mean}±{error}', ha='center', va='bottom', fontsize=10)
    
    plt.tight_layout()
    plt.show()

def main():
    """主函数，运行所有样式定制示例"""
    print("Matplotlib 样式定制演示")
    print("=" * 50)
    
    style_gallery()
    color_schemes()
    font_customization()
    line_styles_markers()
    advanced_customization()
    
    try:
        seaborn_integration()
    except ImportError:
        print("Seaborn未安装，跳过Seaborn集成示例")
    
    custom_theme_example()
    publication_ready_plots()
    
    print("\n样式定制演示完成！")
    print("样式定制要点：")
    print("- 使用plt.style.context()临时应用样式")
    print("- 通过rcParams全局设置样式")
    print("- 合理搭配颜色方案")
    print("- 注意字体大小和可读性")
    print("- 学术图表需要简洁专业")

if __name__ == "__main__":
    main() 